package com.protocols.sctp.m3ua;
import java.rmi.*;

import java.rmi.registry.*;

import java.rmi.server.*;
import java.util.Arrays;
import java.util.Properties;
import java.util.Random;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.*;

import com.Main.MyServiceInterface;
import com.Main.ReceiveMessageInterface;
import com.protocols.sctp.m3ua.sccp.SccpHandler;
import com.protocols.sctp.m3ua.sccp.SccpUnitDataMsg;
import com.protocols.GeneralProtocolData;
import com.protocols.ProtoOperations;
import com.protocols.sctp.TcpHandler;
import com.protocols.sctp.SctpHandlerInterface;
import com.protocols.sctp.m3ua.sccp.SccpHandlerInterface;
import com.protocols.sctp.m3ua.sccp.tcap.camel.CamelHandler;


 

public class M3uaHandler extends java.rmi.server.UnicastRemoteObject implements M3uaHandlerInterface,MyServiceInterface{

	// Configuring the Logger
	
	SctpHandlerInterface SctpHandler;
	SccpHandlerInterface SccpHandler;
	Boolean isM3uaUp=false;	
	private Registry Registry;  
    Logger Log = Logger.getLogger(this.getClass().getName());
    Boolean logInfoEnabled=false;
    
    // Default Configuration
    int layerServiceport=9001;
	String sctphandlerurl= "SctpHandler";
	String m3uahandlerurl= "M3uaHandler";
	String sccphandlerurl= "SccpHandler";
	int ConnRetry=3000;		
	String logfile= "var/log/m3ua.log";
	Level loglevel= Level.OFF;
	private Boolean initasp=false;
    
	public M3uaHandler() throws RemoteException  {	
		super();
		
		
	}

	
	
	
	public void initialise() throws Exception {	
		
		Properties properties=null;
		try{			
			properties = new java.util.Properties();
			properties.load( new FileInputStream("General.conf"));
		}catch( IOException e){
			System.out.println("Couldn't locate the Config File");				
			System.exit(0);
		}			
		logfile= properties.getProperty("m3ua.log.filepath");
		loglevel= Level.parse(properties.getProperty("m3ua.log.level"));
		
		FileHandler filehandler=null;
		try{
			filehandler= new FileHandler(logfile,true);
			filehandler.setFormatter(new SimpleFormatter());
			Log.addHandler(filehandler);
			Log.setLevel(loglevel);				
		}catch( IOException e){
			System.out.println("Issue Opening the Log File. Setting the Log Level to 'OFF'");	
			Log.setLevel(Level.OFF);	
		}
		
		logInfoEnabled=Log.isLoggable(Level.INFO);	
		
		layerServiceport=Integer.valueOf(properties.getProperty("layerservice.port"));
		sctphandlerurl= properties.getProperty("sctp.layerservice.url");
		m3uahandlerurl= properties.getProperty("m3ua.layerservice.url");
		sccphandlerurl= properties.getProperty("sccp.layerservice.url");
		ConnRetry=Integer.valueOf(properties.getProperty("connectionretryinterval"));		
		initasp=properties.getProperty("m3ua.initasp").equals("yes");
			
		try{
			Registry = LocateRegistry.createRegistry( layerServiceport );
			if(logInfoEnabled)Log.info("Created Registry on Port:"+layerServiceport);
		}catch(RemoteException e){
			Registry = LocateRegistry.getRegistry( layerServiceport );	
			if(logInfoEnabled)Log.info("Obtained Registry from Port:"+layerServiceport);
		}
			
		
		Registry.rebind(m3uahandlerurl, this);			
		if(logInfoEnabled)Log.info("Bound M3ua Handler on Url:"+m3uahandlerurl);
		
		
			

		
	}

	public void establishSctpConnection() throws Exception
	{
		Boolean retry=true;
		while(retry)
		{
			try{
				SctpHandler=(SctpHandlerInterface)(Registry.lookup(sctphandlerurl));
				retry=false;
			}catch(Exception e){	
				Log.severe("Couldn't Obtained the SCTPHandler Instance. Retry in "+ConnRetry+" Secs."+"Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));
				Thread.sleep(ConnRetry);
			}
		}
		if(logInfoEnabled)Log.info("Obtained SCTPHandler Instance");
	}
	
	
	public void establishSccpConnection() throws Exception
	{
		Boolean retry=true;
		while(retry)
		{
			try{
				SccpHandler=(SccpHandlerInterface)(Registry.lookup(sccphandlerurl));
				retry=false;
			}catch(Exception e){	
				Log.severe("Couldn't Obtained the Sccp Instance. Retry in "+ConnRetry+" Secs."+"Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));
				Thread.sleep(ConnRetry);
			}
		}				
		if(logInfoEnabled)Log.info("ObtainedSccpHandler Instance");
				
	}
	
	@Override
	public GeneralProtocolData sctpToM3ua(long sessionid,byte[] input)  {
		try{
			if (input[0]==1 && input[2]==3 && input[3]==1){ // ASP Up
				if(logInfoEnabled)Log.info(sessionid+":Received ASPUP");			
				M3uaASPUPAck aspupack = new M3uaASPUPAck();
				if(logInfoEnabled)Log.info(sessionid+":Sending the  ASPUpAck:");		
				return aspupack;	// Sending the ASPUp Ack
			}
			else if (input[0]==1 && input[2]==3 && input[3]==4){	// ASP Ack
				if(logInfoEnabled)Log.info(sessionid+":Received ASPUp Ack");			
				M3uaASPAC aspac = new M3uaASPAC();
				//aspac.RoutingContext.setRoutingContext(2112);			
				if(logInfoEnabled)Log.info(sessionid+":Sending the  ASPAC:");		
				return aspac;	// Sending the ASPAC
				
			}
			else if (input[0]==1 && input[2]==4 && input[3]==1){		// ASPAC
				if(logInfoEnabled)Log.info(sessionid+":Received ASPAC");			
				M3uaASPACAck aspacack = new M3uaASPACAck();
				aspacack.RoutingContext.setRoutingContext(2112);			
				if(logInfoEnabled)Log.info(sessionid+":Sending the  ASPAC Ack:");		
				return aspacack;	// Sending the ASPAC Ack
			}
			else if (input[0]==1 && input[2]==4 && input[3]==3){		// ASPAC ack
				if(logInfoEnabled)Log.info(sessionid+":Received ASPAC Ack");	
				if(logInfoEnabled)Log.info(sessionid+":M3UA Layer is Up..........");
				isM3uaUp=true;
				return null;
			}
			else if (input[0]==1 && input[2]==3 && input[3]==3){		// Beat
				if(logInfoEnabled)Log.info(sessionid+":Received Beat");	
				M3uaBeatAck beakack = new M3uaBeatAck();
				return beakack;
			}
			else if (input[0]==1 && input[2]==0 && input[3]==0){		// Error
				Log.warning(sessionid+":Received M3UA Error");	
				return null;
			}
			else if (input[0]==1 && input[2]==0 && input[3]==1){		// Notify
				if(logInfoEnabled)Log.info(sessionid+":Received M3UA Notify");	
				return null;
			}
			else if (input[0]==1 && input[2]==1 && input[3]==1){	// Payload Data
				if(logInfoEnabled)Log.info(sessionid+":Received M3UA Protocol Data");	
				M3uaPayLoadData m3uadata = new M3uaPayLoadData();
				byte [] payload =m3uadata.decode(input);	

				if (m3uadata.ProtocolData.getServiceIndicator()==3){
					GeneralProtocolData sccp=SccpHandler.m3uaToSccp(sessionid, payload, m3uadata.ProtocolData.getOPC(),m3uadata.ProtocolData.getDPC() );					
					if (sccp==null)
					{
						if(logInfoEnabled)Log.info(sessionid+":Received 'null' Response from SCCP");	
						return null;
					}
					else
					{
						if(logInfoEnabled)Log.info(sessionid+":Received Response from SCCP");	
						m3uadata.ProtocolData.toggleDestination();
						m3uadata.ProtocolData.Payload=sccp;
						return m3uadata;
					}
				}

			}
			else{
				Log.warning(sessionid+":Byte Array received from SCTP layer not identified:"+ProtoOperations.getHexString(input));
			}
		}catch(Exception e){
			Log.severe(sessionid+":Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));

		}
	
		return null;
	}




	@Override
	public void sccpToM3ua(long sessionid, GeneralProtocolData sccpdata) {
		try{
			if(logInfoEnabled)Log.info(sessionid+":Message Received from SCCP");
			M3uaPayLoadData m3uapayload = new M3uaPayLoadData();
			
			//m3uapayload.NetworkAppearance.setNetworkAppearance(2);
			//m3uapayload.RoutingContext.setRoutingContext(2112);
			m3uapayload.ProtocolData.setOPC(2112);
			m3uapayload.ProtocolData.setDPC(2011);
			m3uapayload.ProtocolData.setNI(2);
			m3uapayload.ProtocolData.setMP(0);
			m3uapayload.ProtocolData.setSLS(1);
			m3uapayload.ProtocolData.setServiceIndicator(3);
			//m3uapayload.CorrelationID.setCorrelationId(322);
			
			m3uapayload.ProtocolData.Payload=sccpdata;
			if(logInfoEnabled)Log.info(sessionid+":Sending M3UA Stream");
			SctpHandler.m3uaToSctp(sessionid, m3uapayload);
		
		}catch(Exception e){
			Log.severe(sessionid+":Exception Occured :" +e.getClass().getSimpleName()+":"+ Arrays.toString(e.getStackTrace()));
	
		}
		
	}

	@Override
	public String ping() throws RemoteException {
		// TODO Auto-generated method stub
		return "Pong";
	}

	@Override
	public void startLayer() throws Exception {
		initialise();
		establishSctpConnection();
		establishSccpConnection();
		if(initasp){
			M3uaASPUP aspup = new M3uaASPUP();			
			SctpHandler.m3uaToSctp(1, aspup);
		} 	
	}
	
	public static void main(String args[]) throws Exception {
		M3uaHandler m3ua = new  M3uaHandler();
		m3ua.initialise();
		m3ua.establishSctpConnection();
		m3ua.establishSccpConnection();
		if(m3ua.initasp){
			M3uaASPUP aspup = new M3uaASPUP();			
			m3ua.SctpHandler.m3uaToSctp(1, aspup);
		} 	
	}

	

   
}